package org.skywalking.apm.agent;
import java.util.List;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.NamedElement;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.utility.JavaModule;
import org.skywalking.apm.agent.junction.SkyWalkingEnhanceMatcher;
import org.skywalking.apm.agent.core.boot.ServiceManager;
import org.skywalking.apm.agent.core.conf.SnifferConfigInitializer;
import org.skywalking.apm.agent.core.logging.EasyLogResolver;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
import org.skywalking.apm.agent.core.plugin.PluginBootstrap;
import org.skywalking.apm.agent.core.plugin.PluginException;
import org.skywalking.apm.agent.core.plugin.PluginFinder;
import org.skywalking.apm.logging.ILog;
import org.skywalking.apm.logging.LogManager;
import java.lang.instrument.Instrumentation;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* The main entrance of sky-waking agent,
* based on javaagent mechanism.
*
* @author wusheng
*/
public class SkyWalkingAgent {
private static final ILog logger;
static {
LogManager.setLogResolver(new EasyLogResolver());
logger = LogManager.getLogger(SkyWalkingAgent.class);
}
/**
* Main entrance.
* Use byte-buddy transform to enhance all classes, which define in plugins.
*
* @param agentArgs
* @param instrumentation
* @throws PluginException
*/
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
SnifferConfigInitializer.initialize();
final PluginFinder pluginFinder = new PluginFinder(new PluginBootstrap().loadPlugins());
ServiceManager.INSTANCE.boot();
new AgentBuilder.Default().type(enhanceClassMatcher(pluginFinder).and(not(isInterface()))).transform(new AgentBuilder.Transformer() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader) {
List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription.getTypeName());
for (AbstractClassEnhancePluginDefine pluginDefine : pluginDefines) {
DynamicType.Builder<?> newBuilder = pluginDefine.define(typeDescription.getTypeName(), builder);
if (newBuilder != null) {
return newBuilder;
}
}
logger.warn("Matched class {}, but enhancement fail.", typeDescription.getTypeName());
return builder;
}
}).with(new AgentBuilder.Listener() {
@Override
public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module,
DynamicType dynamicType) {
}
@Override
public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
}
@Override
public void onError(String typeName, ClassLoader classLoader, JavaModule module, Throwable throwable) {
logger.error("Failed to enhance class " + typeName, throwable);
}
@Override
public void onComplete(String typeName, ClassLoader classLoader, JavaModule module) {
}
}).installOn(instrumentation);
}
/**
* Get the enhance target classes matcher.
*
* @param pluginFinder
* @param <T>
* @return class matcher.
*/
private static <T extends NamedElement> ElementMatcher.Junction<T> enhanceClassMatcher(PluginFinder pluginFinder) {
return new SkyWalkingEnhanceMatcher<T>(pluginFinder);
}
}